package cn.backpackerxl.easyJDBC.util;

import cn.backpackerxl.easyJDBC.annotation.DFormat;

import java.lang.reflect.Field;
import java.util.*;

public final class AddDateRule implements JSONParseRule {
    private boolean isArray;
    private boolean isList;
    private boolean isMap;


    @Override
    public boolean evaluate(JSONExpression jsonExpression) {
        boolean eval = false;
        this.isArray = jsonExpression.getField().getType().getTypeName().equals("java.util.Date[]");
        this.isList = jsonExpression.getTypeName().equals("java.util.List<java.util.Date>");
        this.isMap = jsonExpression.getTypeName().equals("java.util.Map<java.lang.String, java.util.Date>");
        if (jsonExpression.getTypeof() == Typeof.DATE || this.isArray || this.isList || this.isMap) {
            this.apply(jsonExpression.getObject(), jsonExpression.getField(), jsonExpression.getJsonObject());
            eval = true;
        }
        return eval;
    }

    private Date toDate(Field field, JSONObject obj) {
        if (field.isAnnotationPresent(DFormat.class)) {
            Time value = field.getDeclaredAnnotation(DFormat.class).value();
            if (value == Time.TIMESTAMP) {
                return obj.toDate();
            } else {
                return obj.toDate(value.get());
            }
        } else {
            return obj.toDate();
        }
    }

    @Override
    public void apply(Object entity, Field field, JSONObject obj) {
        try {
            if (this.isArray) {
                Object[] objects = obj.getArrays().stream().map(jsonObject -> this.toDate(field, jsonObject)).toArray();
                Date[] arr = Arrays.copyOf(objects, objects.length, Date[].class);
                field.set(entity, arr);
            } else if (this.isList) {
                List<Date> list = new ArrayList<>();
                this.applyList(obj, field, list);
                field.set(entity, list);
            } else if (this.isMap) {
                Map<String, Date> map = new HashMap<>();
                this.applyMap(obj, field, map);
                field.set(entity, map);
            } else {
                field.set(entity, this.toDate(field, obj));
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public void applyList(JSONObject obj, Field field, List<Date> list) {
        for (JSONObject jsonObject : obj.getArrays()) {
            list.add(this.toDate(field, jsonObject));
        }
    }

    public void applyMap(JSONObject obj, Field field, Map<String, Date> map) {
        for (JSONObject object : obj.getArrays()) {
            for (String s : object.getObjValue().keySet()) {
                map.put(s, this.toDate(field, object.getObjValue().get(s)));
            }
        }
    }
}
